#pragma once
//I/O多路转接之select
#include"Socket.hpp"
#include"log.hpp"
#include<poll.h>
static const uint16_t defaultport=8888;//默认设置的端口号，静态全局变量的作用域只在它所在的源文件中有效
//static const int max_num=sizeof(fd_set)*8;//一个字节等于8比特位，表示最大可关心的文件描述符数量
static const int defaultfd=-1;//默认文件描述符为-1
static const int fd_nums=64;
int non_event=0;
class PollServer
{
    public:
    PollServer(const uint16_t&port=defaultport)
    :port_(port)//构造时初始化列表
    {
        //函数体赋值
        for(int i=0;i<fd_nums;i++)
        {
            event_fds[i].fd=defaultfd;
            event_fds[i].events=non_event;
            event_fds[i].revents=non_event;
        }

    }
    bool Init()
    {
        //服务器初始化
        listensock_.Socket();//创建套接字
        listensock_.Bind(port_);//绑定套接字
        listensock_.Linsten();//监听，让服务器处于监听的状态（等待被链接）
        lg(INFO,"Server Init sucess!!");
        return true;//初始化完成返回ture

    }
    void PrintFd()
    {
        for(int i=0;i<fd_nums;i++)
        {
            if(event_fds[i].fd==defaultfd)continue;
            std::cout<<event_fds[i].fd<<" ";
        }
    }
    void Accept()
    {
        //处理listensock上面的读事件（有人连接进来）
            std::string clientip;
            uint16_t clientport;
          int sockfd= listensock_.Accept(&clientport,&clientip);
           if(sockfd>0)
           {
             lg(INFO,"Accept sucess ,ip:port is %s:%d  ,sockfd is :%d",clientip.c_str(),clientport,sockfd);
            //把sockfe加入fdarr数组中维护（用来设进rfds中）
            int pos=1;//第一个位置留个linstenfd
            for(;pos<fd_nums;pos++)//第二次循环
            {
                if(event_fds[pos].fd!=defaultfd)continue;//找空位
                else
                break;
            }
            if(pos==fd_nums)
            {
                //没有位置
                lg(WARNING,"fd_arr IS FULL!!");
                close(sockfd);
            }
            else
            {
                event_fds[pos].fd=sockfd;
                event_fds[pos].events=POLLIN;
                PrintFd();//打印一下fd数组
            }
           }
           else
           {
            lg(WARNING,"Accept fail!!");
            return;
           }

    }
    void Recver(int sockfd,int pos)
    {
        //读取fd
             
           char buffer[1024];
          ssize_t n= read(sockfd,buffer,sizeof(buffer)-1);//这里不会阻塞
          if(n>0)
          {
            buffer[n-1]=0;
            std::cout<<buffer<<std::endl;
          }
          else if(n==0)
          {
            //读取到文件末尾
            lg(INFO,"Read to the end of the file!!");
            close(sockfd);//关掉文件描述
            event_fds[pos].fd=defaultfd;//并不需再关心
          }
          else
          {
            //读取出错
            lg(WARNING,"Read err!!");
            close(sockfd);
            event_fds[pos].fd=defaultfd;
          }
          
    }
    void Dispatcher()
    {
        for(int i=0;i<fd_nums;i++)
        {
            int fd=event_fds[i].fd;//获取fd
            if(fd==defaultfd)continue;
            if(event_fds[i].revents&POLLIN)//表示读事件就绪
            {
                if(fd==listensock_.Fd())
                {
                    Accept();//如果是listensock获取连接
                }
                else
                {
                    //否则对其进行读取数据
                    Recver(fd,i);
                }
            }
        }
    }
    void Start()
    {
        int listenfd=listensock_.Fd();
        event_fds[0].fd=listenfd;//数组第一个位置设为listenfd
        event_fds[0].events=POLLIN;//关注可读

        //服务器运行
        for(;;)
        {
            
            //1.让os帮忙关注读写错误事件，当事件发生了再通知再进行读写，或者获取连接
            int timeout=3000;//3秒关心一次
            int n=poll(event_fds,fd_nums,timeout);
            switch(n)
            {
                case 0://超时，没有错误，没有fd就绪0
                lg(INFO,"Not at the ready!! ");
                break;
                case -1://等待出错
                lg(WARNING,"Select Error!!");
                break;
                default://事件就绪
                lg(INFO,"At the ready!!");//事件就绪要处理，否则一直通知

                //怎么处理？派发事件
                Dispatcher();

                break;
            }
       
        }

    }
    ~PollServer()
    {
        listensock_.Close();
    }
    private:
    uint16_t port_;//服务器绑定的端口
    Sock listensock_;//实现好的套接字的类
    struct pollfd event_fds[fd_nums];//定长数组
};